package com.beautiful.xin.map;

/**
 * @author xuqingxin 2021/7/22 11:49 上午
 */
public class ConcurentHashMapTest {

    /**
     *
     * <pre>
     * final V putVal(K key, V value, boolean onlyIfAbsent) {
     *         if (key == null || value == null) throw new NullPointerException();
     *         //计算hash值
     *         int hash = spread(key.hashCode());
     *         int binCount = 0;
     *         //死循环 何时插入成功 何时跳出
     *          （1）数组要插入的位置没有值 （2）链表或树中插入成功
     *         for (Node<K,V>[] tab = table;;) {
     *             Node<K,V> f; int n, i, fh;
     *             //如果table为空的话，初始化table
     *             if (tab == null || (n = tab.length) == 0)
     *                 tab = initTable();
     *             //根据hash值计算出在table里面的位置 question*******2
     * 长度16或其他2的幂次方，Length - 1的值的二进制所有的位均为1，这种情况下，Index的结果等于hashCode的最后几位。只要输入的hashCode本身符合均匀分布，Hash算法的结果就是均匀的。
     * 一句话，HashMap的长度为2的幂次方的原因是为了减少Hash碰撞，尽量使Hash算法的结果均匀分布。
     *             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
     *             	//如果这个位置没有值 ，直接放进去，不需要加锁
     *                 if (casTabAt(tab, i, null,
     *                              new Node<K,V>(hash, key, value, null)))
     *                     break;                   // no lock when adding to empty bin
     *             }
     *             //帮助扩容
     *             else if ((fh = f.hash) == MOVED)
     *                 tab = helpTransfer(tab, f);
     *             else {
     *                 V oldVal = null;
     *                 //锁住桶中的头结点，保证之后插入的并发安全
     *                 synchronized (f) {
     *                     if (tabAt(tab, i) == f) {
     *                         //fh〉0 说明这个节点是一个链表的节点 不是树的节点  spread方法保证了结果非负数
     *                         if (fh >= 0) {
     *                             binCount = 1;
     *                             //在这里遍历链表所有的结点
     *                             for (Node<K,V> e = f;; ++binCount) {
     *                                 K ek;
     *                                 //如果hash值和key值相同 onlyIfAbsent=false 则覆盖对应结点的value值
     *                                 if (e.hash == hash &&
     *                                     ((ek = e.key) == key ||
     *                                      (ek != null && key.equals(ek)))) {
     *                                     oldVal = e.val;
     *                                     if (!onlyIfAbsent)
     *                                         e.val = value;
     *                                     break;
     *                                 }
     *                                 Node<K,V> pred = e;
     *                                 //如果遍历到了最后一个结点，那么就证明新的节点需要插入 就把它插入在链表尾部
     *                                 if ((e = e.next) == null) {
     *                                     pred.next = new Node<K,V>(hash, key,
     *                                                               value, null);
     *                                     break;
     *                                 }
     *                             }
     *                         }
     *                         //如果这个节点是树节点，就按照树的方式插入值（还没太研究明白。。。）
     *                         else if (f instanceof TreeBin) {
     *                             Node<K,V> p;
     *                             binCount = 2;
     *                             if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
     *                                                            value)) != null) {
     *                                 oldVal = p.val;
     *                                 if (!onlyIfAbsent)
     *                                     p.val = value;
     *                             }
     *                         }
     *                     }
     *                 }
     *                 if (binCount != 0) {
     *                 	//如果链表长度已经达到临界值8 （treeifyBin 中会再次判断数组长度>64） 就需要把链表转换为树结构
     *
     *                     //某个桶的元素大小超过了8个，达到了转换为红黑树的阈值，但是数组的长度<64，此
     *                     //时只是通过扩容来解决容量问题，而不会转换为红黑树，而过数组长度>=64，则可以
     *                     //转换为红黑树；
     *
     *                     if (binCount >= TREEIFY_THRESHOLD)
     *                         treeifyBin(tab, i);
     *                     if (oldVal != null)
     *                         return oldVal;
     *                     break;
     *                 }
     *             }
     *         }
     *         //将当前ConcurrentHashMap的元素数量+1
     *         addCount(1L, binCount);
     *         return null;
     *     }
     *     </pre>
     */


}
